// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Text;
using System.IO;
using System.Web;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Xml.Serialization;
using System.Xml;

namespace InterpriseSuiteEcommerceCommon
{

    /// <summary>
    /// This class in only intended to be access from the Customer class
    /// </summary>
    /// 
    [Serializable]
    public class CustomerSession
    {
        //private Guid _customerGuid;
        private Guid _contactGuid;
        private int m_SessionID;
        private DateTime m_LastActivity;
        private string m_IPAddress;
        private Hashtable m_SessionParms;


        /// <summary>
        /// Used only to create an empty customersession object for anonymous customer no data is saved to the database
        /// </summary>
        public CustomerSession()
        {
            //_customerGuid = Guid.Empty;
            _contactGuid = Guid.Empty;
            m_SessionID = 0;
            m_LastActivity = DateTime.MinValue;
            m_IPAddress = "0.0.0.0";
            m_SessionParms = new Hashtable();
        }

        public CustomerSession(Guid contactGUID)
        {
            m_SessionParms = new Hashtable();
            _contactGuid = contactGUID;
            LoadFromDB();
        }

        public CustomerSession(int sessionid, bool ParamIsNotUsedJustForOverloadSemantics)
        {
            m_SessionParms = new Hashtable();
            LoadFromDB(sessionid);
        }

        public void Clear()
        {
            StaticClear(_contactGuid);
        }

        public void ClearVal(String ParamName)
        {
            ParamName = ParamName.ToLowerInvariant();
            if (m_SessionID != 0 && m_SessionParms.ContainsKey(ParamName))
            {
                m_SessionParms.Remove(ParamName);
                UpdateCustomerSession(null, null);
            }
        }

        private void LoadFromDB()
        {
            bool found = false;

            using (var con = DB.NewSqlConnection())
            {
                con.Open();
                using (var rs = DB.GetRSFormat(con, "exec EcommerceSessionGetByContactGuid @ContactGUID={0}, @LastActivity={1}", DB.SQuote(_contactGuid.ToString()), DB.SQuote(Localization.ToDBDateTimeString(DateTime.Now))))
                {
                    if (rs.Read())
                    {
                        found = true;
                        _contactGuid = new Guid(DB.RSFieldGUID(rs, "ContactGUID"));
                        m_SessionID = DB.RSFieldInt(rs, "CustomerSessionID");
                        m_LastActivity = DB.RSFieldDateTime(rs, "LastActivity");
                        m_IPAddress = DB.RSField(rs, "IPAddress");
                        string sessionparams = DB.RSField(rs, "SessionValue");
                        DeserializeParams(sessionparams);
                    }
                    else
                    {
                        found = false;
                    }
                }
            }

            if (!found)
            {
                int sessionid = CustomerSession.CreateSession(_contactGuid, "", "", CommonLogic.ServerVariables("REMOTE_ADDR"));
                LoadFromDB(sessionid);
            }
        }

        private void LoadFromDB(int sessionid)
        {
            using (var con = DB.NewSqlConnection())
            {
                con.Open();
                using (var rs = DB.GetRSFormat(con, "EcommerceSessionGetByID @CustomerSessionID = {0}, @LastActivity = {1}", sessionid.ToString(), DB.SQuote(Localization.ToDBDateTimeString(DateTime.Now))))
                {
                    if (rs.Read())
                    {
                        _contactGuid = new Guid(DB.RSFieldGUID(rs, "CustomerGuid"));
                        m_SessionID = sessionid;
                        m_LastActivity = DB.RSFieldDateTime(rs, "LastActivity");
                        m_IPAddress = DB.RSField(rs, "IPAddress");
                        string sessionparams = DB.RSField(rs, "SessionValue");
                        DeserializeParams(sessionparams);
                    }
                    else
                    {
                        m_SessionID = 0;
                    }
                }
            }
        }

        public static string UpdateCustomerSession(int CustomerSessionID, string SessionParams, string ExpiresOn, object LoggedOut)
        {
            string err = String.Empty;
            SqlConnection cn = new SqlConnection(DB.GetDBConn());
            cn.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "dbo.EcommerceSessionUpdate";

            cmd.Parameters.Add(new SqlParameter("@CustomerSessionID", SqlDbType.Int, 4));
            cmd.Parameters.Add(new SqlParameter("@SessionName", SqlDbType.NVarChar, 200));
            cmd.Parameters.Add(new SqlParameter("@SessionValue", SqlDbType.NText));
            cmd.Parameters.Add(new SqlParameter("@ExpiresOn", SqlDbType.DateTime));
            cmd.Parameters.Add(new SqlParameter("@LastActivity", SqlDbType.DateTime));
            cmd.Parameters.Add(new SqlParameter("@LoggedOut", SqlDbType.DateTime));

            cmd.Parameters["@CustomerSessionID"].Value = CustomerSessionID;
            cmd.Parameters["@SessionName"].Value = "";

            if (SessionParams == null)
            {
                cmd.Parameters["@SessionValue"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@SessionValue"].Value = SessionParams;
            }

            if (ExpiresOn == null)
            {
                cmd.Parameters["@ExpiresOn"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@ExpiresOn"].Value = ExpiresOn;
            }

            if (LoggedOut == null)
            {
                cmd.Parameters["@LoggedOut"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@LastActivity"].Value = DateTime.Now;
            }

            cmd.Parameters["@SessionValue"].Value = DBNull.Value;

            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                err = ex.Message;
            }

            cn.Close();
            cmd.Dispose();
            cn.Dispose();
            return err;
        }

        public static int CreateSession(Guid customerGuid, string ParamName, string sessionValue, string ipAddress)
        {
            ParamName = ParamName.ToLowerInvariant();

            int SessionID = 0;
            string err = String.Empty;
            SqlConnection cn = new SqlConnection(DB.GetDBConn());
            cn.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "dbo.EcommerceSessionInsert";

            cmd.Parameters.Add(new SqlParameter("@CustomerGuid", SqlDbType.UniqueIdentifier));
            cmd.Parameters.Add(new SqlParameter("@SessionValue", SqlDbType.NText));
            cmd.Parameters.Add(new SqlParameter("@IPAddress", SqlDbType.VarChar, 15));
            cmd.Parameters.Add(new SqlParameter("@CustomerSessionID", SqlDbType.Int, 4)).Direction = ParameterDirection.Output;
            cmd.Parameters.Add(new SqlParameter("@ContactGuid", SqlDbType.UniqueIdentifier));

            cmd.Parameters["@CustomerGuid"].Value = customerGuid;
            cmd.Parameters["@ContactGuid"].Value = customerGuid;

            StringBuilder sessionparams = new StringBuilder(1024);
            sessionparams.Append("<params>");
            if (ParamName != null && ParamName != "")
            {
                sessionparams.Append("<param name=\"");
                sessionparams.Append(XmlCommon.XmlEncodeAttribute(ParamName));
                sessionparams.Append("\" val=\"");
                sessionparams.Append(XmlCommon.XmlEncodeAttribute(sessionValue));
                sessionparams.Append("\"/>");
            }
            sessionparams.Append("</params>");
            cmd.Parameters["@SessionValue"].Value = sessionparams.ToString();

            if (ipAddress == null)
            {
                cmd.Parameters["@IPAddress"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@IPAddress"].Value = ipAddress;
            }

            try
            {
                cmd.ExecuteNonQuery();
                SessionID = Convert.ToInt32(cmd.Parameters["@CustomerSessionID"].Value);
            }
            catch (Exception ex)
            {
                err = ex.Message;
            }

            cn.Close();
            cmd.Dispose();
            cn.Dispose();
            return SessionID;
        }

        public static CustomerSession CreateCustomerSession(Guid customerGuid, string SessionName, string SessionValue, string ipaddr)
        {

            CustomerSession cs = null;
            string err = String.Empty;
            SqlConnection cn = new SqlConnection(DB.GetDBConn());
            cn.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "dbo.EcommerceSessionInsert";

            cmd.Parameters.Add(new SqlParameter("@CustomerGuid", SqlDbType.UniqueIdentifier));
            cmd.Parameters.Add(new SqlParameter("@SessionValue", SqlDbType.NText));
            cmd.Parameters.Add(new SqlParameter("@IPAddress", SqlDbType.VarChar, 15));
            cmd.Parameters.Add(new SqlParameter("@CustomerSessionID", SqlDbType.Int, 4)).Direction = ParameterDirection.Output;
            cmd.Parameters.Add(new SqlParameter("@ContactGuid", SqlDbType.UniqueIdentifier));

            cmd.Parameters["@CustomerGuid"].Value = customerGuid;
            cmd.Parameters["@ContactGuid"].Value = customerGuid;

            StringBuilder sessionparams = new StringBuilder(1024);
            sessionparams.Append("<params>");
            if (SessionName != null && SessionName != "")
            {
                sessionparams.Append("<param name=\"");
                sessionparams.Append(XmlCommon.XmlEncodeAttribute(SessionName));
                sessionparams.Append("\" val=\"");
                sessionparams.Append(XmlCommon.XmlEncodeAttribute(SessionValue));
                sessionparams.Append("\"/>");
            }
            sessionparams.Append("</params>");
            cmd.Parameters["@SessionValue"].Value = sessionparams.ToString();

            if (ipaddr == null)
            {
                cmd.Parameters["@IPAddress"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@IPAddress"].Value = ipaddr;
            }

            try
            {
                cmd.ExecuteNonQuery();
                int SessionID = Convert.ToInt32(cmd.Parameters["@CustomerSessionID"].Value);
                cs = new CustomerSession(SessionID, false);
            }
            catch (Exception ex)
            {
                err = ex.Message;
            }

            cn.Close();
            cmd.Dispose();
            cn.Dispose();
            return cs;
        }

        public static void StaticClear()
        {
            StaticClear(Guid.Empty);
        }

        public static void StaticClear(Guid customerGuid)
        {
            DB.ExecuteSQL(
                "exec EcommerceSessionAge @CurrentDate = {0}, @CustomerGuid = {1}",
                DB.SQuote(Localization.ToDBDateTimeString(DateTime.Now)),
                CommonLogic.IIF(customerGuid == Guid.Empty, "NULL", DB.SQuote(customerGuid.ToString()))
            );
        }

        public string UpdateCustomerSession(string ExpiresOn, object LoggedOut)
        {
            if (m_SessionID == 0)
            {
                return "";
            }

            if (LoggedOut != null)
            {
                Clear();
                return "";
            }

            string err = String.Empty;
            SqlConnection cn = new SqlConnection(DB.GetDBConn());
            cn.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "dbo.EcommerceSessionUpdate";

            cmd.Parameters.Add(new SqlParameter("@CustomerSessionID", SqlDbType.Int, 4));
            cmd.Parameters.Add(new SqlParameter("@SessionName", SqlDbType.NVarChar, 200));
            cmd.Parameters.Add(new SqlParameter("@SessionValue", SqlDbType.NText));
            cmd.Parameters.Add(new SqlParameter("@ExpiresOn", SqlDbType.DateTime));
            cmd.Parameters.Add(new SqlParameter("@LastActivity", SqlDbType.DateTime));
            cmd.Parameters.Add(new SqlParameter("@LoggedOut", SqlDbType.DateTime, 30));


            cmd.Parameters["@CustomerSessionID"].Value = m_SessionID;
            cmd.Parameters["@SessionName"].Value = "";

            cmd.Parameters["@SessionValue"].Value = SerializeParams();


            if (ExpiresOn == null)
            {
                cmd.Parameters["@ExpiresOn"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@ExpiresOn"].Value = ExpiresOn;
            }

            if (LoggedOut == null)
            {
                cmd.Parameters["@LoggedOut"].Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters["@LoggedOut"].Value = LoggedOut;
            }

            cmd.Parameters["@LastActivity"].Value = DateTime.Now;

            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                err = ex.Message;
            }

            cn.Close();
            cmd.Dispose();
            cn.Dispose();

            return err;
        }

        public void SetVal(String ParamName, String SessionValue)
        {
            SetVal(ParamName, SessionValue, DateTime.MaxValue);
        }

        public void SetVal(String ParamName, String SessionValue, System.DateTime ExpiresOn)
        {
            ParamName = ParamName.ToLowerInvariant();

            if (m_SessionID == 0)
            {
                return;
            }

            if (m_SessionParms.ContainsKey(ParamName))
            {
                if (SessionValue.Length == 0)
                {
                    m_SessionParms.Remove(ParamName);
                }
                else
                {
                    SessionParam sp = (SessionParam)m_SessionParms[ParamName];
                    sp.ParamValue = SessionValue; ;
                    sp.ExpireOn = ExpiresOn;
                }
                if (m_SessionID != 0)
                {
                    UpdateCustomerSession(null, null);
                }
            }
            else
            {
                if (SessionValue.Length > 0)
                {
                    SessionParam sp = new SessionParam(ParamName, SessionValue, ExpiresOn);
                    m_SessionParms.Add(ParamName, sp);
                    if (m_SessionID != 0)
                    {
                        UpdateCustomerSession(null, null);
                    }
                }
            }
        }

        public void SetVal(String ParamName, int NewValue, System.DateTime ExpiresOn)
        {
            SetVal(ParamName, NewValue.ToString(), ExpiresOn);
        }

        public void SetVal(String ParamName, Single NewValue, System.DateTime ExpiresOn)
        {
            SetVal(ParamName, NewValue.ToString(), ExpiresOn);
        }

        public void SetVal(String ParamName, decimal NewValue, System.DateTime ExpiresOn)
        {
            SetVal(ParamName, NewValue.ToString(), ExpiresOn);
        }

        public void SetVal(String ParamName, System.DateTime NewValue, System.DateTime ExpiresOn)
        {
            SetVal(ParamName, NewValue.ToString(), ExpiresOn);
        }

        public String Session(String ParamName)
        {
            ParamName = ParamName.ToLowerInvariant();
            String tmpS = String.Empty;
            try
            {
                if (m_SessionParms.Contains(ParamName))
                {
                    SessionParam sp = (SessionParam)m_SessionParms[ParamName.ToLowerInvariant().Trim()];
                    tmpS = sp.ParamValue;
                }
                else
                {
                    tmpS = string.Empty;
                }
            }
            catch
            {
                tmpS = String.Empty;
            }
            return tmpS;
        }

        public bool SessionBool(String paramName)
        {
            String tmpS = Session(paramName);

            return "TRUE".Equals(tmpS, StringComparison.InvariantCultureIgnoreCase) ||
                    "YES".Equals(tmpS, StringComparison.InvariantCultureIgnoreCase) ||
                    "1".Equals(tmpS, StringComparison.InvariantCultureIgnoreCase);            
        }

        public int SessionUSInt(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseUSInt(tmpS);
        }

        public long SessionUSLong(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseUSLong(tmpS);
        }

        public Single SessionUSSingle(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseUSSingle(tmpS);
        }

        public Decimal SessionUSDecimal(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseUSDecimal(tmpS);
        }

        public DateTime SessionUSDateTime(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseUSDateTime(tmpS);
        }

        public int SessionNativeInt(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseNativeInt(tmpS);
        }

        public long SessionNativeLong(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseNativeLong(tmpS);
        }

        public Single SessionNativeSingle(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseNativeSingle(tmpS);
        }

        public Decimal SessionNativeDecimal(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseNativeDecimal(tmpS);
        }

        public DateTime SessionNativeDateTime(String paramName)
        {
            String tmpS = Session(paramName);
            return Localization.ParseNativeDateTime(tmpS);
        }

        public string this[string ParamName]
        {
            get { return this.Session(ParamName); }
            set { this.SetVal(ParamName, value); }
        }


        public int SessionID
        {
            get { return m_SessionID; }
        }

        public DateTime LastActivity
        {
            get { return m_LastActivity; }
        }


        private string SerializeParams()
        {

            StringBuilder sb = new StringBuilder("<params>", 1024);
            foreach (string s in m_SessionParms.Keys)
            {
                SessionParam sp = (SessionParam)m_SessionParms[s];
                sb.Append("<param name=\"" + XmlCommon.XmlEncodeAttribute(s) + "\" val=\"" + XmlCommon.XmlEncodeAttribute(sp.ParamValue) + "\" " + CommonLogic.IIF(sp.ExpireOn == DateTime.MaxValue, "", "expireon=\"" + Localization.DateTimeStringForDB(sp.ExpireOn) + "\"") + " />");
            }
            sb.Append("</params>");
            return sb.ToString();
        }

        private void DeserializeParams(string s)
        {
            XmlDocument x = new XmlDocument();
            x.LoadXml(s);
            foreach (XmlNode n in x.SelectNodes("//param"))
            {
                if (n.Attributes["name"] != null)
                {
                    DateTime expireon = DateTime.MaxValue;
                    if (n.Attributes["expireon"] != null)
                    {
                        expireon = DateTime.Parse(n.Attributes["expireon"].InnerText);
                    }
                    if (expireon > DateTime.Now)
                    {
                        SessionParam sp = new SessionParam(n.Attributes["name"].InnerText, n.Attributes["val"].InnerText, expireon);
                        m_SessionParms.Add(n.Attributes["name"].InnerText.ToLowerInvariant(), sp);
                    }
                }
            }
        }

    }

    [Serializable]
    public class SessionParam
    {
        public string ParamName;
        public string ParamValue;
        public DateTime ExpireOn;

        public SessionParam(string paramname, string paramvalue, DateTime expireon)
        {
            ParamName = paramname.ToLowerInvariant();
            ParamValue = paramvalue;
            ExpireOn = expireon;
        }
    }
}














